package com.xhj.mybatis.scripting.xmltags;

import ognl.Ognl;
import ognl.OgnlException;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * OgnlCache
 *
 * @author XJks
 * @description 缓存 OGNL 解析后的表达式节点，提升表达式解析效率。
 */
public final class OgnlCache {

    /**
     * OGNL 的成员访问控制器，用于限制表达式访问 Java 对象的成员
     */
    private static final OgnlMemberAccess MEMBER_ACCESS = new OgnlMemberAccess();

    /**
     * OGNL 的类解析器，用于自定义类加载逻辑
     */
    private static final OgnlClassResolver CLASS_RESOLVER = new OgnlClassResolver();

    /**
     * 用于缓存表达式解析结果，key 为表达式字符串，value 为解析后的节点对象
     */
    private static final Map<String, Object> expressionCache = new ConcurrentHashMap<>();

    /**
     * 私有构造方法，防止外部实例化该工具类
     */
    private OgnlCache() {
        // 阻止实例化静态工具类
    }

    /**
     * 解析并计算 OGNL 表达式的值
     *
     * @param expression OGNL 表达式字符串
     * @param root       表达式的根对象
     * @return 表达式计算结果
     */
    public static Object getValue(String expression, Object root) {
        try {
            // 创建 OGNL 上下文环境，包含根对象、成员访问控制器、类解析器等
            Map context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, null);
            // 解析表达式并计算结果
            return Ognl.getValue(parseExpression(expression), context, root);
        } catch (OgnlException e) {
            // 解析或计算过程中出现异常，直接抛出异常
            throw new RuntimeException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
        }
    }

    /**
     * 解析 OGNL 表达式并缓存解析结果
     *
     * @param expression OGNL 表达式字符串
     * @return 解析后的表达式节点对象
     * @throws OgnlException 解析失败时抛出异常
     */
    private static Object parseExpression(String expression) throws OgnlException {
        // 先从缓存中获取解析结果
        Object node = expressionCache.get(expression);
        if (node == null) {
            // 缓存中没有则解析表达式
            node = Ognl.parseExpression(expression);
            // 将解析结果放入缓存
            expressionCache.put(expression, node);
        }
        // 返回解析结果
        return node;
    }

}
